/*!
 * upload 文件上传组件
 * MIT Licensed
 */

import $ from 'jquery';
import layui from "./layui";
import layer from "./layer";

var hint = layui.hint()
	, device = layui.device()

	//外部接口
	, upload = {
		config: {} //全局配置项

		//设置全局项
		, set: function (options) {
			var that = this;
			that.config = $.extend({}, that.config, options);
			return that;
		}

		//事件
		, on: function (events, callback) {
			return layui.onevent.call(this, MOD_NAME, events, callback);
		}
	}

	//操作当前实例
	, thisUpload = function () {
		var that = this;
		return {
			upload: function (files) {
				that.upload.call(that, files);
			}
			, reload: function (options) {
				that.reload.call(that, options);
			}
			, config: that.config
		}
	}

	//字符常量
	, MOD_NAME = 'upload', ELEM = 'layui-upload', THIS = 'layui-this', SHOW = 'layui-show', HIDE = 'layui-hide',
	DISABLED = 'layui-disabled'

	, ELEM_FILE = 'layui-upload-file', ELEM_FORM = 'layui-upload-form', ELEM_IFRAME = 'layui-upload-iframe',
	ELEM_CHOOSE = 'layui-upload-choose', ELEM_DRAG = 'layui-upload-drag'


	//构造器
	, Class = function (options) {
		var that = this;
		that.config = $.extend({}, that.config, upload.config, options);
		that.render();
	};

//默认配置
Class.prototype.config = {
	accept: 'images' //允许上传的文件类型：images/file/video/audio
	, exts: '' //允许上传的文件后缀名
	, auto: true //是否选完文件后自动上传
	, bindAction: '' //手动上传触发的元素
	, url: '' //上传地址
	, field: 'file' //文件字段名
	, acceptMime: '' //筛选出的文件类型，默认为所有文件
	, method: 'post' //请求上传的 http 类型
	, data: {} //请求上传的额外参数
	, drag: true //是否允许拖拽上传
	, size: 0 //文件限制大小，默认不限制
	, number: 0 //允许同时上传的文件数，默认不限制
	, multiple: false //是否允许多文件上传，不支持ie8-9
};

//初始渲染
Class.prototype.render = function () {
	var that = this
		, options = that.config;

	options.elem = $(options.elem);
	options.bindAction = $(options.bindAction);

	that.file();
	that.events();
};

//追加文件域
Class.prototype.file = function () {
	var that = this
		, options = that.config
		, elemFile = that.elemFile = $([
		'<input class="' + ELEM_FILE + '" type="file" accept="' + options.acceptMime + '" name="' + options.field + '"'
		, (options.multiple ? ' multiple' : '')
		, '>'
	].join(''))
		, next = options.elem.next();

	if (next.hasClass(ELEM_FILE) || next.hasClass(ELEM_FORM)) {
		next.remove();
	}

	//包裹ie8/9容器
	if (device.ie && device.ie < 10) {
		options.elem.wrap('<div class="layui-upload-wrap"></div>');
	}

	that.isFile() ? (
		that.elemFile = options.elem
			, options.field = options.elem[0].name
	) : options.elem.after(elemFile);

	//初始化ie8/9的Form域
	if (device.ie && device.ie < 10) {
		that.initIE();
	}
};

//ie8-9初始化
Class.prototype.initIE = function () {
	var that = this
		, options = that.config
		,
		iframe = $('<iframe id="' + ELEM_IFRAME + '" class="' + ELEM_IFRAME + '" name="' + ELEM_IFRAME + '" frameborder="0"></iframe>')
		,
		elemForm = $(['<form target="' + ELEM_IFRAME + '" class="' + ELEM_FORM + '" method="post" key="set-mine" enctype="multipart/form-data" action="' + options.url + '">'
			, '</form>'].join(''));

	//插入iframe
	$('#' + ELEM_IFRAME)[0] || $('body').append(iframe);

	//包裹文件域
	if (!options.elem.next().hasClass(ELEM_FORM)) {
		that.elemFile.wrap(elemForm);

		//追加额外的参数
		options.elem.next('.' + ELEM_FORM).append(function () {
			var arr = [];
			layui.each(options.data, function (key, value) {
				value = typeof value === 'function' ? value() : value;
				arr.push('<input type="hidden" name="' + key + '" value="' + value + '">')
			});
			return arr.join('');
		}());
	}
};

//异常提示
Class.prototype.msg = function (content) {
	return layer.msg(content, {
		icon: 2
		, shift: 6
	});
};

//判断绑定元素是否为文件域本身
Class.prototype.isFile = function () {
	var elem = this.config.elem[0];
	if (!elem) return;
	return elem.tagName.toLocaleLowerCase() === 'input' && elem.type === 'file'
}

//预读图片信息
Class.prototype.preview = function (callback) {
	var that = this;
	if (window.FileReader) {
		layui.each(that.chooseFiles, function (index, file) {
			var reader = new FileReader();
			reader.readAsDataURL(file);
			reader.onload = function () {
				callback && callback(index, file, this.result);
			}
		});
	}
};

//执行上传
Class.prototype.upload = function (files, type) {
	var that = this
		, options = that.config
		, elemFile = that.elemFile[0]

		//高级浏览器处理方式，支持跨域
		, ajaxSend = function () {
			var successful = 0, aborted = 0
				, items = files || that.files || that.chooseFiles || elemFile.files
				, allDone = function () { //多文件全部上传完毕的回调
				if (options.multiple && successful + aborted === that.fileLength) {
					typeof options.allDone === 'function' && options.allDone({
						total: that.fileLength
						, successful: successful
						, aborted: aborted
					});
				}
			};
			layui.each(items, function (index, file) {
				var formData = new FormData();

				formData.append(options.field, file);

				//追加额外的参数
				layui.each(options.data, function (key, value) {
					value = typeof value === 'function' ? value() : value;
					formData.append(key, value);
				});

				//提交文件
				var opts = {
					url: options.url
					, type: 'post' //统一采用 post 上传
					, data: formData
					, contentType: false
					, processData: false
					, dataType: 'json'
					, headers: options.headers || {}
					//成功回调
					, success: function (res) {
						successful++;
						done(index, res);
						allDone();
					}
					//异常回调
					, error: function () {
						aborted++;
						that.msg('请求上传接口出现异常');
						error(index);
						allDone();
					}
				};
				//进度条
				if (typeof options.progress === 'function') {
					opts.xhr = function () {
						var xhr = $.ajaxSettings.xhr();
						//上传进度
						xhr.upload.addEventListener("progress", function (obj) {
							if (obj.lengthComputable) {
								var percent = Math.floor((obj.loaded / obj.total) * 100); //百分比
								options.progress(percent, (options.item ? options.item[0] : options.elem[0]), obj, index);
							}
						});
						return xhr;
					}
				}
				$.ajax(opts);
			});
		}

		//低版本IE处理方式，不支持跨域
		, iframeSend = function () {
			var iframe = $('#' + ELEM_IFRAME);

			that.elemFile.parent().submit();

			//获取响应信息
			clearInterval(Class.timer);
			Class.timer = setInterval(function () {
				var res, iframeBody = iframe.contents().find('body');
				try {
					res = iframeBody.text();
				} catch (e) {
					that.msg('获取上传后的响应信息出现异常');
					clearInterval(Class.timer);
					error();
				}
				if (res) {
					clearInterval(Class.timer);
					iframeBody.html('');
					done(0, res);
				}
			}, 30);
		}

		//统一回调
		, done = function (index, res) {
			that.elemFile.next('.' + ELEM_CHOOSE).remove();
			elemFile.value = '';
			if (typeof res !== 'object') {
				try {
					res = JSON.parse(res);
				} catch (e) {
					res = {};
					return that.msg('请对上传接口返回有效JSON');
				}
			}
			typeof options.done === 'function' && options.done(res, index || 0, function (files) {
				that.upload(files);
			});
		}

		//统一网络异常回调
		, error = function (index) {
			if (options.auto) {
				elemFile.value = '';
			}
			typeof options.error === 'function' && options.error(index || 0, function (files) {
				that.upload(files);
			});
		}

		, exts = options.exts
		, check, value = function () {
			var arr = [];
			layui.each(files || that.chooseFiles, function (i, item) {
				arr.push(item.name);
			});
			return arr;
		}()

		//回调返回的参数
		, args = {
			//预览
			preview: function (callback) {
				that.preview(callback);
			}
			//上传
			, upload: function (index, file) {
				var thisFile = {};
				thisFile[index] = file;
				that.upload(thisFile);
			}
			//追加文件到队列
			, pushFile: function () {
				that.files = that.files || {};
				layui.each(that.chooseFiles, function (index, item) {
					that.files[index] = item;
				});
				return that.files;
			}
			//重置文件
			, resetFile: function (index, file, filename) {
				var newFile = new File([file], filename);
				that.files = that.files || {};
				that.files[index] = newFile;
			}
		}

		//提交上传
		, send = function () {
			//选择文件的回调
			if (type === 'choose' || options.auto) {
				options.choose && options.choose(args);
				if (type === 'choose') {
					return;
				}
			}

			//上传前的回调 - 如果回调函数明确返回false，则停止上传(#pulls55)
			if (options.before && (options.before(args) === false)) return;

			//IE兼容处理
			if (device.ie) {
				return device.ie > 9 ? ajaxSend() : iframeSend();
			}

			ajaxSend();
		}

	//校验文件格式
	value = value.length === 0
		? ((elemFile.value.match(/[^\/\\]+\..+/g) || []) || '')
		: value;

	if (value.length === 0) return;

	switch (options.accept) {
		case 'file': //一般文件
			if (exts && !RegExp('\\w\\.(' + exts + ')$', 'i').test(escape(value))) {
				that.msg('选择的文件中包含不支持的格式');
				return elemFile.value = '';
			}
			break;
		case 'video': //视频文件
			if (!RegExp('\\w\\.(' + (exts || 'avi|mp4|wma|rmvb|rm|flash|3gp|flv') + ')$', 'i').test(escape(value))) {
				that.msg('选择的视频中包含不支持的格式');
				return elemFile.value = '';
			}
			break;
		case 'audio': //音频文件
			if (!RegExp('\\w\\.(' + (exts || 'mp3|wav|mid') + ')$', 'i').test(escape(value))) {
				that.msg('选择的音频中包含不支持的格式');
				return elemFile.value = '';
			}
			break;
		default: //图片文件
			layui.each(value, function (i, item) {
				if (!RegExp('\\w\\.(' + (exts || 'jpg|png|gif|bmp|jpeg$') + ')', 'i').test(escape(item))) {
					check = true;
				}
			});
			if (check) {
				that.msg('选择的图片中包含不支持的格式');
				return elemFile.value = '';
			}
			break;
	}

	//检验文件数量
	that.fileLength = function () {
		var length = 0
			, items = files || that.files || that.chooseFiles || elemFile.files;
		layui.each(items, function () {
			length++;
		});
		return length;
	}();
	if (options.number && that.fileLength > options.number) {
		return that.msg('同时最多只能上传的数量为：' + options.number);
	}

	//检验文件大小
	if (options.size > 0 && !(device.ie && device.ie < 10)) {
		var limitSize;

		layui.each(that.chooseFiles, function (index, file) {
			if (file.size > 1024 * options.size) {
				var size = options.size / 1024;
				size = size >= 1 ? (size.toFixed(2) + 'MB') : options.size + 'KB'
				elemFile.value = '';
				limitSize = size;
			}
		});
		if (limitSize) return that.msg('文件不能超过' + limitSize);
	}
	send();
};

//重置方法
Class.prototype.reload = function (options) {
	options = options || {};
	delete options.elem;
	delete options.bindAction;

	var that = this;
	options = that.config = $.extend({}, that.config, upload.config, options)
	var next = options.elem.next();

	//更新文件域相关属性
	next.attr({
		name: options.name
		, accept: options.acceptMime
		, multiple: options.multiple
	});
};

//事件处理
Class.prototype.events = function () {
	var that = this
		, options = that.config

		//设置当前选择的文件队列
		, setChooseFile = function (files) {
			that.chooseFiles = {};
			layui.each(files, function (i, item) {
				var time = new Date().getTime();
				that.chooseFiles[time + '-' + i] = item;
			});
		}

		//设置选择的文本
		, setChooseText = function (files, filename) {
			var elemFile = that.elemFile
				, item = options.item ? options.item : options.elem
				, value = files.length > 1
				? files.length + '个文件'
				: ((files[0] || {}).name || (elemFile[0].value.match(/[^\/\\]+\..+/g) || []) || '');

			if (elemFile.next().hasClass(ELEM_CHOOSE)) {
				elemFile.next().remove();
			}
			that.upload(null, 'choose');
			if (that.isFile() || options.choose) return;
			elemFile.after('<span class="layui-inline ' + ELEM_CHOOSE + '">' + value + '</span>');
		};

	//点击上传容器
	options.elem.off('upload.start').on('upload.start', function () {
		var othis = $(this), data = othis.attr('lay-data');

		if (data) {
			try {
				data = new Function('return ' + data)();
				that.config = $.extend({}, options, data);
			} catch (e) {
				hint.error('Upload element property lay-data configuration item has a syntax error: ' + data)
			}
		}

		that.config.item = othis;
		that.elemFile[0].click();
	});

	//拖拽上传
	if (!(device.ie && device.ie < 10)) {
		options.elem.off('upload.over').on('upload.over', function () {
			var othis = $(this)
			othis.attr('lay-over', '');
		})
			.off('upload.leave').on('upload.leave', function () {
			var othis = $(this)
			othis.removeAttr('lay-over');
		})
			.off('upload.drop').on('upload.drop', function (e, param) {
			var othis = $(this), files = param.originalEvent.dataTransfer.files || [];

			othis.removeAttr('lay-over');
			setChooseFile(files);

			if (options.auto) {
				that.upload(files);
			} else {
				setChooseText(files);
			}
		});
	}

	//文件选择
	that.elemFile.off('upload.change').on('upload.change', function () {
		var files = this.files || [];
		setChooseFile(files);
		options.auto ? that.upload() : setChooseText(files); //是否自动触发上传
	});

	//手动触发上传
	options.bindAction.off('upload.action').on('upload.action', function () {
		that.upload();
	});

	//防止事件重复绑定
	if (options.elem.data('haveEvents')) return;

	that.elemFile.on('change', function () {
		$(this).trigger('upload.change');
	});

	options.elem.on('click', function () {
		if (that.isFile()) return;
		$(this).trigger('upload.start');
	});

	if (options.drag) {
		options.elem.on('dragover', function (e) {
			e.preventDefault();
			$(this).trigger('upload.over');
		}).on('dragleave', function (e) {
			$(this).trigger('upload.leave');
		}).on('drop', function (e) {
			e.preventDefault();
			$(this).trigger('upload.drop', e);
		});
	}

	options.bindAction.on('click', function () {
		$(this).trigger('upload.action');
	});

	options.elem.data('haveEvents', true);
};

//核心入口
upload.render = function (options) {
	var inst = new Class(options);
	return thisUpload.call(inst);
};

export default upload;

